package com.example.demo.config;


import cn.hutool.core.bean.BeanUtil;
import com.example.demo.common.convention.result.Results;
import com.example.demo.dao.entity.Account;
import com.example.demo.dto.response.AuthorizeVO;
import com.example.demo.filter.JsonAuthenticationFilter;
import com.example.demo.filter.JwtAuthenticationFilter;
import com.example.demo.filter.RequestLogFilter;
import com.example.demo.service.AccountService;
import com.example.demo.utils.Const;
import com.example.demo.utils.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;

import static com.example.demo.common.convention.errorcode.BaseErrorCode.JWT_NULL_ERROR;

/**
 * SpringSecurity相关配置
 */
@Configuration
@RequiredArgsConstructor
public class SecurityConfiguration {


    final JwtAuthenticationFilter jwtAuthenticationFilter;


    final RequestLogFilter requestLogFilter;


    final JwtUtils utils;


    final AccountService service;


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authManager) throws Exception {
        JsonAuthenticationFilter jsonAuthFilter =
                new JsonAuthenticationFilter(authManager,this::handleProcess,this::handleProcess);

        return http
                .authorizeHttpRequests(conf -> conf
                        .requestMatchers("/api/account/**").permitAll()
                        .requestMatchers("/api/qrcode/getQRCode").hasAnyRole(Const.ROLE_DEFAULT)
                        .requestMatchers("/api/captcha/getCaptchaResult").hasAnyRole(Const.ROLE_DEFAULT)
                        .requestMatchers("/api/captcha/getCaptcha").hasAnyRole(Const.ROLE_DEFAULT)
                        .anyRequest().permitAll()
                )
                .logout(conf -> conf
                        .logoutUrl("/api/account/logout")
                        .logoutSuccessHandler(this::onLogoutSuccess)

                )
                .exceptionHandling(conf -> conf
                        .accessDeniedHandler(this::handleProcess)
                        .authenticationEntryPoint(this::handleProcess)
                )
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(conf -> conf
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 启用并配置CORS
                .addFilterBefore(jsonAuthFilter, UsernamePasswordAuthenticationFilter.class) // 使用自定义的JSON过滤器
                .addFilterBefore(requestLogFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(jwtAuthenticationFilter, RequestLogFilter.class)
                .build();
    }

    /**
     * 将多种类型的Handler整合到同一个方法中，包含：
     * - 登录成功
     * - 登录失败
     * - 未登录拦截/无权限拦截
     * @param request 请求
     * @param response 响应
     * @param exceptionOrAuthentication 异常或是验证实体
     * @throws IOException 可能的异常
     */
    private void handleProcess(HttpServletRequest request,
                               HttpServletResponse response,
                               Object exceptionOrAuthentication) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        if(exceptionOrAuthentication instanceof AccessDeniedException exception) {
            writer.write(Results.forbidden(exception.getMessage()).asJsonString());

        } else if(exceptionOrAuthentication instanceof Exception exception) {
            writer.write(Results
                    .unauthorized(exception.getMessage()).asJsonString());
        } else if(exceptionOrAuthentication instanceof Authentication authentication){
            User user = (User) authentication.getPrincipal();
            System.out.println(user);
            Account account = service.findAccountByUserName(user.getUsername());
            String jwt = utils.createJwt(user, account.getUsername(), account.getId());
            if(jwt == null) {
                writer.write(Results.forbidden("登录验证频繁，请稍后再试").asJsonString());
            } else {

                AuthorizeVO vo = BeanUtil.copyProperties(account, AuthorizeVO.class);
                vo.setToken(jwt);
                vo.setExpire(utils.expireTime());
                writer.write(Results.success(vo).asJsonString());
                System.out.println(Results.success(vo).asJsonString());
            }
        }
    }

    /**
     * 退出登录处理，将对应的Jwt令牌列入黑名单不再使用
     * @param request 请求
     * @param response 响应
     * @param authentication 验证实体
     * @throws IOException 可能的异常
     */
    private void onLogoutSuccess(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Authentication authentication) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        String authorization = request.getHeader("Authorization");
        if(utils.invalidateJwt(authorization)) {
            writer.write(Results.success().asJsonString());
            return;
        }
        writer.write(Results.failure(JWT_NULL_ERROR.code(), JWT_NULL_ERROR.message()).asJsonString());
    }
    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        return http.getSharedObject(AuthenticationManagerBuilder.class).build();
    }
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000", "https://yourdomain.com"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
        configuration.setAllowCredentials(true);
        configuration.setExposedHeaders(List.of("Authorization"));

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration); // 应用到所有路径

        return source;
    }
}
